package com.god.gl.blue;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * @author gl
 * @date 2021/1/29
 * @desc
 */
@SuppressLint("NewApi")
public class HidConnectUtil {
    private static final String TAG = "HidConnectUtil";
    private BluetoothDevice mDevice;
    private Context mContext;
    private BluetoothAdapter mBluetoothAdapter;
    private ArrayList<BluetoothDevice> hidConnectList = new ArrayList<BluetoothDevice>();
    private GetHidConncetListListener getHidConncetListListener;

    private static HidConnectUtil instance = null;

    private HidConnectUtil(Context context) {
        this.mContext = context;
        this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    public static HidConnectUtil getInstance() {
        if (instance == null) {
            instance = new HidConnectUtil(App.getContext());
        }
        return instance;
    }

    /**
     * 蓝牙扫描
     */
    public void startScan() {
        if (null != mBluetoothAdapter) {
            Log.e(TAG, "startScan");
            if (mBluetoothAdapter.isDiscovering()) {
                mBluetoothAdapter.cancelDiscovery();
            }
            mBluetoothAdapter.startDiscovery();
        }
    }

    /**
     * 停止扫描
     */
    public void stopScan() {
        if (null != mBluetoothAdapter) {
            Log.e(TAG, "stopScan");
            mBluetoothAdapter.cancelDiscovery();
        }
    }


    /**
     * 判断是否支持蓝牙，若支持 判断是否打开 ，没有打开，则打开
     *
     * @return
     */
    public boolean isSupportBluetooth() {
        if (null == mBluetoothAdapter) {
            Toast.makeText(mContext, "不支持蓝牙功能", Toast.LENGTH_LONG).show();
            return false;
        }
        if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
        }
        return true;

    }


    /**
     * 获取BluetoothProfile中hid的profile，"INPUT_DEVICE"类型隐藏，需反射获取
     *
     * @return
     */
    @SuppressLint("NewApi")
    public static int getInputDeviceHiddenConstant() {
        Class<BluetoothProfile> clazz = BluetoothProfile.class;
        for (Field f : clazz.getFields()) {
            int mod = f.getModifiers();
            if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
                try {
                    String type;
                    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        type = "HID_HOST";
                    } else {
                        type = "INPUT_DEVICE";
                    }
                    if (f.getName().equals(type)) {
                        return f.getInt(null);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }

    /**
     * 通过getHidConncetListListener.getSuccess(hidConncetList);回调
     */
    private BluetoothProfile.ServiceListener getList = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            try {
                if (profile == getInputDeviceHiddenConstant()) {
                    hidConnectList.clear();
                    List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
                    for (BluetoothDevice bluetoothDevice : connectedDevices) {
                        hidConnectList.add(bluetoothDevice);
                    }
                }
                getHidConncetListListener.getSuccess(hidConnectList);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(int profile) {

        }
    };


    /**
     * 连接设备
     *
     * @param bluetoothDevice
     */
    public void connect(final BluetoothDevice bluetoothDevice) {
        mDevice = bluetoothDevice;
        try {
            mBluetoothAdapter.getProfileProxy(mContext,
                    connect, getInputDeviceHiddenConstant());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看BluetoothInputDevice源码，connect(BluetoothDevice device)该方法可以连接HID设备，但是查看BluetoothInputDevice这个类
     * 是隐藏类，无法直接使用，必须先通过BluetoothProfile.ServiceListener回调得到BluetoothInputDevice，然后再反射connect方法连接
     */
    private BluetoothProfile.ServiceListener connect = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            //BluetoothProfile proxy这个已经是BluetoothInputDevice类型了
            try {
                if (profile == getInputDeviceHiddenConstant()) {
                    if (mDevice != null) {
                        //得到BluetoothInputDevice然后反射connect连接设备
                        Method method = proxy.getClass().getMethod("connect",
                                new Class[]{BluetoothDevice.class});
                        method.invoke(proxy, mDevice);

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(int profile) {

        }
    };


    /**
     * 断开连接
     *
     * @param bluetoothDevice
     */
    public void disConnect(BluetoothDevice bluetoothDevice) {
        mDevice = bluetoothDevice;
        try {
            mBluetoothAdapter.getProfileProxy(mContext, disConnect, getInputDeviceHiddenConstant());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private BluetoothProfile.ServiceListener disConnect = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            try {
                if (profile == getInputDeviceHiddenConstant()) {
                    List<BluetoothDevice> connectedDevices = proxy
                            .getConnectedDevices();
                    for (BluetoothDevice bluetoothDevice : connectedDevices) {
                        hidConnectList.add(bluetoothDevice);
                    }
                    if (mDevice != null) {
                        Method method = proxy.getClass().getMethod("disconnect",
                                new Class[]{BluetoothDevice.class});
                        method.invoke(proxy, mDevice);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(int profile) {

        }
    };

    /**
     * 配对
     *
     * @param bluetoothDevice
     */
    public void pair(BluetoothDevice bluetoothDevice) {
        mDevice = bluetoothDevice;
        Method createBondMethod;
        try {
            createBondMethod = BluetoothDevice.class.getMethod("createBond");
            createBondMethod.invoke(mDevice);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 取消配对
     *
     * @param bluetoothDevice
     */
    public void unPair(BluetoothDevice bluetoothDevice) {
        mDevice = bluetoothDevice;
        Method createBondMethod;
        try {
            createBondMethod = BluetoothDevice.class.getMethod("removeBond");
            createBondMethod.invoke(mDevice);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 判断蓝牙是否配对
     *
     * @param bluetoothDevice
     * @return
     */
    public boolean isPair(BluetoothDevice bluetoothDevice) {
        int state = bluetoothDevice.getBondState();
        if (state == BluetoothDevice.BOND_NONE) {
            return false;
        } else if (state == BluetoothDevice.BOND_NONE) {
            return true;
        }
        return false;

    }


    /**
     * 得到已经配对的列表
     *
     * @return
     */
    private List<BluetoothDevice> getPairList() {
        Set<BluetoothDevice> mSet = mBluetoothAdapter.getBondedDevices();
        final Iterator mIterator = mSet.iterator();
        List<BluetoothDevice> list = new ArrayList<>();
        while (mIterator.hasNext()) {
            BluetoothDevice bluetoothDevice = (BluetoothDevice) mIterator.next();
            list.add(bluetoothDevice);
        }
        return list;
    }


    /**
     * 判断是否连接
     *
     * @param bluetoothDevice
     */
    private void isConnected(BluetoothDevice bluetoothDevice) {
        getHidConncetList(new HidConnectUtil.GetHidConncetListListener() {
            @Override
            public void getSuccess(ArrayList<BluetoothDevice> list) {
                //判断连接列表中是否有该设备
                for (BluetoothDevice bluetooth : list) {
                    if (bluetoothDevice.getAddress().equals(bluetooth.getAddress())) {
                        break;
                    }
                }
            }
        });
    }

    /**
     * 得到所有HID连接的设备列表
     *
     * @param getHidConncetListListener
     */
    public void getHidConncetList(GetHidConncetListListener getHidConncetListListener) {
        this.getHidConncetListListener = getHidConncetListListener;
        try {
            mBluetoothAdapter.getProfileProxy(mContext, getList, getInputDeviceHiddenConstant());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public interface GetHidConncetListListener {
        public void getSuccess(ArrayList<BluetoothDevice> list);
    }


}

